#ifndef EXP_SIZE_HPP
#define EXP_SIZE_HPP
#include<type_traits>
namespace exp_utilities
{
    namespace exp_size_details {
        template<class TL>
        concept has_length = requires { TL::length; };
        template<class TL>
        struct type_list_size
        {
            static constexpr std::size_t value = 0;
        };

        template<class TL> requires has_length<TL>
        struct type_list_size<TL>
        {
            static constexpr std::size_t value = TL::length;
        };

        template<template<class...> class TL, class ...Tys>
        struct type_list_size<TL<Tys...>>
        {
            static constexpr std::size_t value = sizeof...(Tys);
        };
    }
    template<class L>
    constexpr std::size_t exp_size = exp_size_details::type_list_size<L>::value;

    namespace max_index_details {
        template<class TL>
        struct max_index_type {
            static_assert((exp_size<TL> > 0), "Error: empty list");
            static constexpr std::size_t value = exp_size<TL> -1;
        };
    }

    template<class L>
    constexpr std::size_t max_index = max_index_details::max_index_type<L>::value;

    template<class L, std::size_t N>
    constexpr bool length_equal = (exp_size<L> == N);

    template<std::size_t N>
    struct length_is {
        template<class L>
        struct apply : std::bool_constant<length_equal<L, N>> {};
    };

    template<std::size_t N>
    struct length_is_not {
        template<class L>
        struct apply : std::bool_constant<!length_equal<L, N>> {};
    };

    template<std::size_t N>
    struct length_less {
        template<class L>
        struct apply : std::bool_constant<exp_size<L> < N> {};
    };

    template<std::size_t N>
    struct length_greater {
        template<class L>
        struct apply : std::bool_constant<(exp_size<L> > N)> {};
    };
}
#endif // !EXP_SIZE_HPP
